#pragma once

#include <KPBR/KPBR.h>

#include <utility>
#include <vector>
#include <map>

struct MtlInfo {
    // params
    float Ns, Ni, d_;
    kp::Vec3f Ka, Kd, Ks, Ke;
    // map path
    std::string map_Kd, map_Ks;
    int illum;
};

struct MeshCache {
    std::vector<kp::Face> faceindices;
    std::vector<kp::Point3f> vertices;
    std::vector<kp::Normal> normals;
    std::vector<kp::Point2f> uvs;
    // [map_name, mat_ref]
    std::map<std::string, kp::Ref<kp::Material>> mat_map;
};

class ObjLoader {
public:
    explicit ObjLoader(const std::string &path);

    /**
     * Get primitives in mesh
     * @param o2w Preset o2w transform
     * @return Triangle primitives
     */
    std::vector<kp::Ref<kp::Primitive>> get(kp::Ref<kp::Transform> o2w);

private:
    void load_obj(const std::string &fileName);

    void load_mtl(const std::string &fileName);

    MeshCache mesh;
    // [start_index, mtl_name]
    std::vector<std::pair<int, std::string>> mtl_list;
    // [mtl_name, mtl_info]
    std::map<std::string, MtlInfo> mtl_map;
};
